package com.app.backend.Interceptor;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.app.backend.base.entity.Permission;
import com.app.backend.base.entity.User;
import com.app.backend.common.constant.LoginConstant;
import com.app.backend.common.response.BaseResponse;
import com.app.backend.common.response.ResponseCode;
import com.app.backend.common.service.RedisValueService;
import com.app.backend.common.utils.RequestContextHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.util.List;


/**
 * @program: UserInterceptor
 * @description:
 * @author: Zhun.Xiao
 * @create: 2018-11-26 11:37
 **/
@Slf4j
public class UserInterceptor implements HandlerInterceptor {

    private final static Logger logger = LoggerFactory.getLogger(UserInterceptor.class);
    @Resource
    private RedisValueService<User> redisValueService;
    @Value("${app-backend.account.expire}")
    private int expireTime;

    /**
     * 判断用户是否有访问权限
     *
     * @param
     * @param uri
     * @return
     */
    public static boolean HasPermission(List<Permission> permissions, String uri) {
        if (uri.indexOf("?") > 0) {
            uri = uri.substring(0, uri.indexOf("?"));
        }
        final String u = uri;
        if (permissions == null) {
            return false;
        }
        return permissions.parallelStream().anyMatch(permission ->
                permission.getUrl().equals(u)
        );
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        // 根据token获取用户 保存ThreadLocal
        String token = request.getHeader(LoginConstant.ACCESS_TOKEN);

        if (StringUtils.isNotBlank(token)) {
            token = URLDecoder.decode(token, "UTF-8");

            User userDo = redisValueService.get(LoginConstant.LOGIN_TOKENS + token);
            log.info("UserInterceptor->preHandle:{}" + userDo);
            if (null == userDo) {
                resultInfo(response, ResponseCode.NO_TOKEN);
                logger.info("---> interceptor --> no user in cache ,token {}", token);
                return false;
            }

            List<Permission> permissions = userDo.getPermissions();
            if (!HasPermission(permissions, request.getRequestURI())) {
                resultInfo(response, ResponseCode.NO_PERMISSION);
                logger.info("---> interceptor --> user has no permission ");
                return false;
            }

            logger.info("---> userDo=" + userDo);
            RequestContextHandler.setCurrentUserToken(token);
            RequestContextHandler.setCurrentUserName(userDo.getUsername());
            RequestContextHandler.setCurrentUserId(userDo.getId());
            RequestContextHandler.setCurrentUserNo(userDo.getUserno());
            logger.info("--> token 校验成功");
            logger.info("--> 刷新用户时效,token :" + token);
            redisValueService.expire(LoginConstant.LOGIN_TOKENS + token, userDo, expireTime);
            return true;

        } else {
            logger.info("---> interceptor token is null");
            resultInfo(response, ResponseCode.NO_TOKEN);
            return false;
        }


    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        RequestContextHandler.remove();
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        RequestContextHandler.remove();

    }

    private void resultInfo(HttpServletResponse response, ResponseCode code) throws Exception {
        BaseResponse resp = new BaseResponse();
        resp.setCode(code);
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        writer.write(JSONObject.toJSONString(resp, SerializerFeature.WriteEnumUsingToString));
        writer.flush();
        writer.close();
    }

}
